/*
 * Copyright (c) 2017-2023, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*!****************************************************************************
 *  @file       AESCCM.h
 *
 *  @brief      AESCCM driver header
 *
 *  @anchor ti_drivers_AESCCM_Overview
 *  # Overview #
 *  The Counter with CBC-MAC (CCM) mode of operation is a generic
 *  authenticated encryption block cipher mode.  It can be used with
 *  any block cipher.
 *  AESCCM combines CBC-MAC with an AES block cipher in CTR mode of operation.
 *
 *  This combination of block cipher modes enables CCM to encrypt messages of any
 *  length and not only multiples of the block cipher block size.
 *
 *  CTR provides confidentiality. The defined application of CBC-MAC provides
 *  message integrity and authentication.
 *
 *  AESCCM has the following inputs and outputs:
 *
 * <table>
 * <caption id="AESCCM_multi_row">AES-CCM input and output parameters</caption>
 * <tr><th>Encryption</th><th>Decryption</th></tr>
 * <tr><th colspan=2>Input</th></tr>
 * <tr><td>Shared AES key</td><td> Shared AES key</td></tr>
 * <tr><td>Nonce</td><td>Nonce</td></tr>
 * <tr><td>Cleartext</td><td>Ciphertext</td></tr>
 * <tr><td></td><td>MAC</td></tr>
 * <tr><td>AAD (optional)</td><td>AAD (optional)</td></tr>
 * <tr><th colspan=2>Output</th></tr>
 * <tr><td>Ciphertext</td><td>Cleartext</td></tr>
 * <tr><td>MAC</td><td></td></tr>
 * </table>
 *
 *  The AES key is a shared secret between the two parties and has a length
 *  of 128, 192, or 256 bits.
 *
 *  The nonce is generated by the party performing the authenticated
 *  encryption operation.  Within the scope of any authenticated
 *  encryption key, the nonce value must be unique.  That is, the set of
 *  nonce values used with any given key must not contain any duplicate
 *  values.  Using the same nonce for two different messages encrypted
 *  with the same key destroys the security properties.
 *
 *  The length of the nonce determines the maximum number of messages that may
 *  be encrypted and authenticated before you must regenerate the key.
 *  Reasonable session key rotation schemes will regenerate the key before reaching
 *  this limit.
 *  There is a trade-off between the nonce-length and the maximum length of
 *  the plaintext to encrypt and authenticate per nonce. This is because
 *  CTR concatenates the nonce and an internal counter into one 16-byte
 *  IV. The counter is incremented after generating an AES-block-sized
 *  pseudo-random bitstream. This bitstream is XOR'd with the plaintext.
 *  The counter would eventually roll over for a sufficiently long message.
 *  This is must not happen. Hence, the longer the nonce and the more messages
 *  you can send before needing to rotate the key, the shorter the
 *  lengths of individual messages sent may be. The minimum and maximum
 *  nonce length defined by the CCM standard provide for both a reasonable
 *  number of messages before key rotation and a reasonable maximum message length.
 *  Check NIST SP 800-38C for details.
 *
 *  The optional additional authentication data (AAD) is authenticated
 *  but not encrypted. Thus, the AAD is not included in the AES-CCM output.
 *  It can be used to authenticate packet headers.
 *
 *  After the encryption operation, the ciphertext contains the encrypted
 *  data. The message authentication code (MAC) is also provided.
 *
 *  # CCM Variations #
 *  The AESCCM driver supports both classic CCM as defined by NIST SP 800-38C and
 *  the CCM* variant used in IEEE 802.15.4.
 *  CCM* allows for unauthenticated encryption using CCM by permitting a MAC length
 *  of 0. It also imposes the requirement that the MAC length be embedded in
 *  the nonce used for each message if the MAC length varies within the protocol
 *  using CCM*.
 *
 *  @anchor ti_drivers_AESCCM_Usage
 *  # Usage #
 *
 *  ## Before starting a CCM operation #
 *
 *  Before starting a CCM operation, the application must do the following:
 *      - Call AESCCM_init() to initialize the driver
 *      - Call AESCCM_Params_init() to initialize the AESCCM_Params to default values.
 *      - Modify the AESCCM_Params as desired
 *      - Call AESCCM_open() to open an instance of the driver
 *      - Initialize a CryptoKey. These opaque data structures are representations
 *        of keying material and its storage. Depending on how the keying material
 *        is stored (RAM or flash, key store), the CryptoKey must be
 *        initialized differently. The AESCCM API can handle all types of CryptoKey.
 *        However, not all device-specific implementations support all types of CryptoKey.
 *        Devices without a key store will not support CryptoKeys with keying material
 *        stored in a key store for example.
 *        All devices support plaintext CryptoKeys.
 *      - Initialize the appropriate AESCCM operation struct using the relevant
 *        operation init functions and set all fields. For example, one-step (one-shot
 *        or single call) operations should initialize AESCCM_Operation or
 *        AESCCM_OneStepOperation using AESCCM_Operation_init() or
 *        AESCCM_OneStepOperation_init(). For multi-step (segmented or multiple call)
 *        operations, AESCCM_SegmentedAADOperation must be initialized and set when
 *        processing AAD. AESCCM_SegmentedDataOperation must be initialized and set when
 *        dealing with payload data (plaintext or ciphertext). AESCCM_SegmentedFinalizeOperation
 *        must be initialized and set when finalizing the segmented operation.
 *
 *  ## Starting a CCM operation #
 *
 *  The AESCCM_oneStepEncrypt and AESCCM_oneStepDecrypt functions do a CCM operation in a single call.
 *  They will always be the most highly optimized routines with the least overhead and the fastest
 *  runtime. However, they require all AAD and plaintext or ciphertext data to be
 *  available to the function at the start of the call.
 *  All devices support single call operations.
 *
 *  When performing a decryption operation with AESCCM_oneStepDecrypt(), the MAC is
 *  automatically verified.
 *
 *  ## After the CCM operation completes #
 *
 *  After the CCM operation completes, the application should either start another operation
 *  or close the driver by calling AESCCM_close()
 *
 *  @anchor ti_drivers_AESCCM_Synopsis
 *  ## Synopsis
 *
 *  @anchor ti_drivers_AESCCM_Synopsis_Code
 *  @code
 *
 *  // Import AESCCM Driver definitions
 *  #include <ti/drivers/AESCCM.h>
 *
 *  // Define name for AESCCM channel index
 *  #define AESCCM_INSTANCE 0
 *
 *  AESCCM_init();
 *
 *  handle = AESCCM_open(AESCCM_INSTANCE, NULL);
 *
 *  // Initialize symmetric key
 *  CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *  // Set up AESCCM_OneStepOperation
 *  AESCCM_OneStepOperation_init(&operation);
 *  operation.key               = &cryptoKey;
 *  operation.aad               = aad;
 *  operation.aadLength         = sizeof(aad);
 *  operation.input             = plaintext;
 *  operation.output            = ciphertext;
 *  operation.inputLength       = sizeof(plaintext);
 *  operation.nonce             = nonce;
 *  operation.nonceLength       = sizeof(nonce);
 *  operation.mac               = mac;
 *  operation.macLength         = sizeof(mac);
 *
 *  encryptionResult = AESCCM_oneStepEncrypt(handle, &operation);
 *
 *  AESCCM_close(handle);
 *  @endcode
 *
 *  @anchor ti_drivers_AESCCM_Examples
 *  ## Examples
 *
 *  ### Single call CCM encryption + authentication with plaintext CryptoKey in blocking return mode #
 *  @code
 *
 *  #include <ti/drivers/AESCCM.h>
 *  #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
 *
 *  ...
 *
 *  AESCCM_Handle handle;
 *  CryptoKey cryptoKey;
 *  int_fast16_t encryptionResult;
 *  uint8_t nonce[] = "Thisisanonce";
 *  uint8_t aad[] = "This string will be authenticated but not encrypted.";
 *  uint8_t plaintext[] = "This string will be encrypted and authenticated.";
 *  uint8_t mac[16];
 *  uint8_t ciphertext[sizeof(plaintext)];
 *  uint8_t keyingMaterial[32] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 *                                0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 *                                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 *                                0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
 *
 *  handle = AESCCM_open(0, NULL);
 *
 *  if (handle == NULL) {
 *      // handle error
 *  }
 *
 *  CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *      AESCCM_OneStepOperation operation;
 *      AESCCM_OneStepOperation_init(&operation);
 *
 *      operation.key               = &cryptoKey;
 *      operation.aad               = aad;
 *      operation.aadLength         = sizeof(aad);
 *      operation.input             = plaintext;
 *      operation.output            = ciphertext;
 *      operation.inputLength       = sizeof(plaintext);
 *      operation.nonce             = nonce;
 *      operation.nonceLength       = sizeof(nonce);
 *      operation.mac               = mac;
 *      operation.macLength         = sizeof(mac);
 *
 *  encryptionResult = AESCCM_oneStepEncrypt(handle, &operation);
 *
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  AESCCM_close(handle);
 *
 *  @endcode
 *  ### The following code snippet is for CC27XX devices only and leverages the HSM
 *      which is a seperate Hardware Accelerator ###
 *  ### Single call CCM encryption + authentication with plaintext HSM CryptoKey in Polling Mode ###
 *
 *  @code
 *
 *  #include <ti/drivers/AESCCM.h>
 *  #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
 *
 *  ...
 *
 *  AESCCM_Params params;
 *  AESCCM_Handle handle;
 *  CryptoKey cryptoKey;
 *  int_fast16_t encryptionResult;
 *  uint8_t nonce[] = "Thisisanonce";
 *  uint8_t aad[] = "This string will be authenticated but not encrypted.";
 *  uint8_t plaintext[] = "This string will be encrypted and authenticated.";
 *  uint8_t mac[16];
 *  uint8_t ciphertext[sizeof(plaintext)];
 *  uint8_t keyingMaterial[32] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 *                                0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 *                                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 *                                0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
 *
 *  AESCCM_Params_init(&params)
 *  params.returnBehavior = AESCCM_RETURN_BEHAVIOR_POLLING;
 *
 *  handle = AESCCM_open(0, &params);
 *
 *  if (handle == NULL) {
 *      // handle error
 *  }
 *
 *  CryptoKeyPlaintextHSM_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *  AESCCM_OneStepOperation operation;
 *  AESCCM_OneStepOperation_init(&operation);
 *
 *  operation.key           = &cryptoKey;
 *  operation.aad           = aad;
 *  operation.aadLength     = sizeof(aad);
 *  operation.input         = plaintext;
 *  operation.output        = ciphertext;
 *  operation.inputLength   = sizeof(plaintext);
 *  operation.nonce         = nonce;
 *  operation.nonceLength   = sizeof(nonce);
 *  operation.mac           = mac;
 *  operation.macLength     = sizeof(mac);
 *
 *  encryptionResult = AESCCM_oneStepEncrypt(handle, &operation);
 *
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  AESCCM_close(handle);
 *
 *  @endcode
 *
 *  ### Single call CCM decryption + verification with plaintext CryptoKey in callback return mode #
 *  @code
 *
 *  #include <ti/drivers/AESCCM.h>
 *  #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
 *
 *  ...
 *
 *  // The following test vector is Packet Vector 1 from RFC 3610 of the IETF.
 *
 *  uint8_t nonce[]                         = {0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0,
 *                                             0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
 *  uint8_t aad[]                           = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
 *  uint8_t mac[]                           = {0x17, 0xE8, 0xD1, 0x2C, 0xFD, 0xF9, 0x26, 0xE0};
 *  uint8_t ciphertext[]                    = {0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2,
 *                                             0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80,
 *                                             0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84};
 *  uint8_t keyingMaterial[]                = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
 *                                             0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF};
 *  uint8_t plaintext[sizeof(ciphertext)];
 *
 *  // The plaintext should be the following after the decryption operation:
 *  //  {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 *  //  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 *  //  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}
 *
 *
 *  void ccmCallback(AESCCM_Handle handle,
 *                   int_fast16_t returnValue,
 *                   AESCCM_OperationUnion *operation,
 *                   AESCCM_OperationType operationType) {
 *
 *      if (returnValue != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *  }
 *
 *  AESCCM_OneStepOperation operation;
 *
 *  void ccmStartFunction(void) {
 *      AESCCM_Handle handle;
 *      AESCCM_Params params;
 *      CryptoKey cryptoKey;
 *      int_fast16_t decryptionResult;
 *
 *      AESCCM_Params_init(&params);
 *      params.returnBehavior = AESCCM_RETURN_BEHAVIOR_CALLBACK;
 *      params.callbackFxn = ccmCallback;
 *
 *      handle = AESCCM_open(0, &params);
 *
 *      if (handle == NULL) {
 *          // handle error
 *      }
 *
 *      CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *      AESCCM_OneStepOperation_init(&operation);
 *
 *      operation.key               = &cryptoKey;
 *      operation.aad               = aad;
 *      operation.aadLength         = sizeof(aad);
 *      operation.input             = ciphertext;
 *      operation.output            = plaintext;
 *      operation.inputLength       = sizeof(ciphertext);
 *      operation.nonce             = nonce;
 *      operation.nonceLength       = sizeof(nonce);
 *      operation.mac               = mac;
 *      operation.macLength         = sizeof(mac);
 *
 *      decryptionResult = AESCCM_oneStepDecrypt(handle, &operation);
 *
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      // do other things while CCM operation completes in the background
 *
 *  }
 *
 *
 *  @endcode
 *
 *  ### Multi-step CCM encryption + authentication with plaintext CryptoKey in blocking return mode #
 *  @code
 *
 *  #include <ti/drivers/AESCCM.h>
 *  #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
 *
 *  ...
 *
 *  #define AES_BLOCK_SIZE     16 // bytes
 *
 *  AESCCM_Handle handle;
 *  CryptoKey cryptoKey;
 *  int_fast16_t encryptionResult;
 *
 *  // The following test vector is Packet Vector 1 from RFC 3610 of the IETF.
 *
 *  uint8_t keyingMaterial[16] = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
 *                                0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF};
 *  uint8_t aad[8]             = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
 *  uint8_t plaintext[23]      = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 *                                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 *                                0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E};
 *  uint8_t nonce[13]          = {0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0,
 *                                0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
 *  uint8_t mac[8];
 *  uint8_t ciphertext[sizeof(plaintext)];
 *
 *  // The ciphertext should be the following after the encryption operation:
 *  //  {0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2,
 *  //  0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80,
 *  //  0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84}
 *
 *  handle = AESCCM_open(0, NULL);
 *
 *  if (handle == NULL) {
 *      // handle error
 *  }
 *
 *  CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *
 *  encryptionResult = AESCCM_setupEncrypt(handle, &cryptoKey, sizeof(aad), sizeof(plaintext), sizeof(mac));
 *  if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  encryptionResult = AESCCM_setNonce(handle, nonce, sizeof(nonce));
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC27XX) // and the HSM is the engine of choice
 *
 *  CryptoKeyPlaintextHSM_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *  // You will also need to populate the mac in handle->object->mac because HSM needs the mac to construct each
 *  // segmented token.
 *  encryptionResult = AESCCMLPF3HSM_setMac(handle, &mac[0], 8);
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  #endif
 *
 *  AESCCM_SegmentedAADOperation segmentedAADOperation;
 *  AESCCM_SegmentedAADOperation_init(&segmentedAADOperation);
 *  segmentedAADOperation.aad = aad;
 *  segmentedAADOperation.aadLength = sizeof(aad);
 *
 *  encryptionResult = AESCCM_addAAD(handle, &segmentedAADOperation);
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  AESCCM_SegmentedDataOperation segmentedDataOperation;
 *  AESCCM_SegmentedDataOperation_init(&segmentedDataOperation);
 *  segmentedDataOperation.input = plaintext;
 *  segmentedDataOperation.output = ciphertext;
 *  // One should pass in data that is a block-sized multiple length
 *  // until passing in the last segment of data.
 *  // In that case, the input length simply needs to be a non-zero value.
 *  segmentedDataOperation.inputLength = AES_BLOCK_SIZE;
 *
 *  encryptionResult = AESCCM_addData(handle, &segmentedDataOperation);
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  segmentedDataOperation.input = plaintext + AES_BLOCK_SIZE;
 *  segmentedDataOperation.output = ciphertext + AES_BLOCK_SIZE;
 *  segmentedDataOperation.inputLength = sizeof(plaintext) - AES_BLOCK_SIZE;
 *
 *  encryptionResult = AESCCM_addData(handle, &segmentedDataOperation);
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  AESCCM_SegmentedFinalizeOperation segmentedFinalizeOperation;
 *  AESCCM_SegmentedFinalizeOperation_init(&egmentedFinalizeOperation);
 *  segmentedFinalizeOperation.input = plaintext;
 *  segmentedFinalizeOperation.output = ciphertext;
 *
 *  // You can finalize with no new data
 *  segmentedFinalizeOperation.inputLength = 0;
 *  segmentedFinalizeOperation.mac = mac;
 *  segmentedFinalizeOperation.macLength = sizeof(mac);
 *  encryptionResult = AESCCM_finalizeEncrypt(handle, &segmentedFinalizeOperation);
 *
 *  if (encryptionResult != AESCCM_STATUS_SUCCESS) {
 *      // handle error
 *  }
 *
 *  AESCCM_close(handle);
 *
 *  @endcode
 *
 *  ### Multi-step CCM decryption + verification with plaintext CryptoKey in callback return mode #
 *  @code
 *
 *  #include <ti/drivers/AESCCM.h>
 *  #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
 *
 *  ...
 *
 *  // The following test vector is Packet Vector 1 from RFC 3610 of the IETF.
 *
 *  uint8_t nonce[]                         = {0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0,
 *                                             0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
 *  uint8_t aad[]                           = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
 *  uint8_t mac[]                           = {0x17, 0xE8, 0xD1, 0x2C, 0xFD, 0xF9, 0x26, 0xE0};
 *  uint8_t ciphertext[]                    = {0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2,
 *                                             0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80,
 *                                             0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84};
 *  uint8_t keyingMaterial[]                = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
 *                                             0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF};
 *  uint8_t plaintext[sizeof(ciphertext)];
 *
 *  // The plaintext should be the following after the decryption operation:
 *  //  {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 *  //  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 *  //  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}
 *
 *
 *  void ccmCallback(AESCCM_Handle handle,
 *                   int_fast16_t returnValue,
 *                   AESCCM_OperationUnion *operation,
 *                   AESCCM_OperationType operationType) {
 *
 *      if (returnValue != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      if(operationType == AESCCM_OPERATION_TYPE_DECRYPT ||
 *         operationType == AESCCM_OPERATION_TYPE_ENCRYPT)
 *      {
 *          // Callback fxn only used for one-shot operations
 *          // Use operation->oneStepOperation
 *      }
 *      else if(operationType == AESCCM_OP_TYPE_AAD_DECRYPT ||
 *              operationType == AESCCM_OP_TYPE_AAD_ENCRYPT)
 *      {
 *          // Callback fxn only used for segmented AAD operations
 *          // Use operation->segmentedAADOperation
 *      }
 *      else if(operationType == AESCCM_OP_TYPE_DATA_DECRYPT ||
 *              operationType == AESCCM_OP_TYPE_DATA_ENCRYPT)
 *      {
 *          // Callback fxn only used for segmented data operations
 *          // Use operation->segmentedDataOperation
 *      }
 *      else
 *      {
 *          // Callback fxn only used for segmented finalize operations
 *          // Use operation->segmentedFinalizeOperation
 *      }
 *  }
 *
 *  void ccmStartFunction(void) {
 *      AESCCM_Handle handle;
 *      AESCCM_Params params;
 *      CryptoKey cryptoKey;
 *      int_fast16_t decryptionResult;
 *
 *      AESCCM_Params_init(&params);
 *      params.returnBehavior = AESCCM_RETURN_BEHAVIOR_CALLBACK;
 *      params.callbackFxn = ccmCallback;
 *
 *      handle = AESCCM_open(0, &params);
 *
 *      if (handle == NULL) {
 *          // handle error
 *      }
 *
 *      CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *      decryptionResult = AESCCM_setupDecrypt(handle, &cryptoKey, 0, 0, 0);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      // setLengths must be called if the AAD, input, and MAC lengths aren't provided in setupXXXX.
 *      decryptionResult = AESCCM_setLengths(handle, sizeof(aad), sizeof(ciphertext), sizeof(mac));
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      decryptionResult = AESCCM_setNonce(handle, nonce, sizeof(nonce));
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      AESCCM_SegmentedAADOperation segmentedAADOperation;
 *      AESCCM_SegmentedAADOperation_init(&segmentedAADOperation);
 *      segmentedAADOperation.aad = aad;
 *      segmentedAADOperation.aadLength = sizeof(aad);
 *
 *      decryptionResult = AESCCM_addAAD(handle, &segmentedAADOperation);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      AESCCM_SegmentedDataOperation segmentedDataOperation;
 *      AESCCM_SegmentedDataOperation_init(&segmentedDataOperation);
 *      segmentedDataOperation.input = ciphertext;
 *      segmentedDataOperation.output = plaintext;
 *      segmentedDataOperation.inputLength = AES_BLOCK_SIZE;
 *
 *      decryptionResult = AESCCM_addData(handle, &segmentedDataOperation);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      AESCCM_SegmentedFinalizeOperation segmentedFinalizeOperation;
 *      AESCCM_SegmentedFinalizeOperation_init(&egmentedFinalizeOperation);
 *      segmentedFinalizeOperation.input = ciphertext + AES_BLOCK_SIZE;
 *      segmentedFinalizeOperation.output = plaintext + AES_BLOCK_SIZE;
 *      segmentedFinalizeOperation.inputLength = sizeof(ciphertext) - AES_BLOCK_SIZE;
 *      segmentedFinalizeOperation.mac = mac;
 *      segmentedFinalizeOperation.macLength = sizeof(mac);
 *
 *      decryptionResult = AESCCM_finalizeDecrypt(handle, &segmentedFinalizeOperation);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      // do other things while CCM operation completes in the background
 *
 *  }
 *
 *  @endcode
 *
 *  ### Multi-step CCM* decryption + verification with plaintext CryptoKey in callback return mode #
 *  @code
 *
 *  #include <ti/drivers/AESCCM.h>
 *  #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
 *
 *  ...
 *
 *  // The following test vector is Packet Vector 1 from RFC 3610 of the IETF.
 *
 *  uint8_t nonce[]                         = {0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0,
 *                                             0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
 *  uint8_t aad[]                           = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
 *  uint8_t mac[]                           = {0};
 *
 *  // CCM* allows for unauthenticated encryption using CCM by allowing a MAC length of 0
 *  uint8_t macLength                       = 0;
 *  uint8_t ciphertext[]                    = {0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2,
 *                                             0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80,
 *                                             0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84};
 *  uint8_t keyingMaterial[]                = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
 *                                             0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF};
 *  uint8_t plaintext[sizeof(ciphertext)];
 *
 *  // The plaintext should be the following after the decryption operation:
 *  //  {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 *  //  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
 *  //  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E}
 *
 *
 *  void ccmCallback(AESCCM_Handle handle,
 *                   int_fast16_t returnValue,
 *                   AESCCM_OperationUnion *operation,
 *                   AESCCM_OperationType operationType) {
 *
 *      if (returnValue != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      if(operationType == AESCCM_OPERATION_TYPE_DECRYPT ||
 *         operationType == AESCCM_OPERATION_TYPE_ENCRYPT)
 *      {
 *          // Callback fxn only used for one-shot operations
 *          // Use operation->oneStepOperation
 *      }
 *      else if(operationType == AESCCM_OP_TYPE_AAD_DECRYPT ||
 *              operationType == AESCCM_OP_TYPE_AAD_ENCRYPT)
 *      {
 *          // Callback fxn only used for segmented AAD operations
 *          // Use operation->segmentedAADOperation
 *      }
 *      else if(operationType == AESCCM_OP_TYPE_DATA_DECRYPT ||
 *              operationType == AESCCM_OP_TYPE_DATA_ENCRYPT)
 *      {
 *          // Callback fxn only used for segmented data operations
 *          // Use operation->segmentedDataOperation
 *      }
 *      else
 *      {
 *          // Callback fxn only used for segmented finalize operations
 *          // Use operation->segmentedFinalizeOperation
 *      }
 *  }
 *
 *  void ccmStartFunction(void) {
 *      AESCCM_Handle handle;
 *      AESCCM_Params params;
 *      CryptoKey cryptoKey;
 *      int_fast16_t decryptionResult;
 *
 *      AESCCM_Params_init(&params);
 *      params.returnBehavior = AESCCM_RETURN_BEHAVIOR_CALLBACK;
 *      params.callbackFxn = ccmCallback;
 *
 *      handle = AESCCM_open(0, &params);
 *
 *      if (handle == NULL) {
 *          // handle error
 *      }
 *
 *      CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));
 *
 *      decryptionResult = AESCCM_setupDecrypt(handle, &cryptoKey, 0, 0, 0);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      // setLengths must be called if the AAD, input, and MAC lengths aren't provided in setupXXXX.
 *      decryptionResult = AESCCM_setLengths(handle, sizeof(aad), sizeof(ciphertext), macLength);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      decryptionResult = AESCCM_setNonce(handle, nonce, sizeof(nonce));
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      AESCCM_SegmentedAADOperation segmentedAADOperation;
 *      AESCCM_SegmentedAADOperation_init(&segmentedAADOperation);
 *      segmentedAADOperation.aad = aad;
 *      segmentedAADOperation.aadLength = sizeof(aad);
 *
 *      decryptionResult = AESCCM_addAAD(handle, &segmentedAADOperation);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      AESCCM_SegmentedDataOperation segmentedDataOperation;
 *      AESCCM_SegmentedDataOperation_init(&segmentedDataOperation);
 *      segmentedDataOperation.input = ciphertext;
 *      segmentedDataOperation.output = plaintext;
 *      segmentedDataOperation.inputLength = AES_BLOCK_SIZE;
 *
 *      decryptionResult = AESCCM_addData(handle, &segmentedDataOperation);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      AESCCM_SegmentedFinalizeOperation segmentedFinalizeOperation;
 *      AESCCM_SegmentedFinalizeOperation_init(&egmentedFinalizeOperation);
 *      segmentedFinalizeOperation.input = ciphertext + AES_BLOCK_SIZE;
 *      segmentedFinalizeOperation.output = plaintext + AES_BLOCK_SIZE;
 *      segmentedFinalizeOperation.inputLength = sizeof(ciphertext) - AES_BLOCK_SIZE;
 *      segmentedFinalizeOperation.mac = mac;
 *      segmentedFinalizeOperation.macLength = macLength;
 *
 *      decryptionResult = AESCCM_finalizeDecrypt(handle, &segmentedFinalizeOperation);
 *      if (decryptionResult != AESCCM_STATUS_SUCCESS) {
 *          // handle error
 *      }
 *
 *      // do other things while CCM operation completes in the background
 *
 *  }
 *
 *  @endcode
 */

#ifndef ti_drivers_AESCCM__include
#define ti_drivers_AESCCM__include

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include <ti/drivers/AESCommon.h>
#include <ti/drivers/cryptoutils/cryptokey/CryptoKey.h>

#ifdef __cplusplus
extern "C" {
#endif

/*!
 * Common AESCCM status code reservation offset.
 * AESCCM driver implementations should offset status codes with
 * AESCCM_STATUS_RESERVED growing negatively.
 *
 * Example implementation specific status codes:
 * @code
 * #define AESCCMXYZ_STATUS_ERROR0    AESCCM_STATUS_RESERVED - 0
 * #define AESCCMXYZ_STATUS_ERROR1    AESCCM_STATUS_RESERVED - 1
 * #define AESCCMXYZ_STATUS_ERROR2    AESCCM_STATUS_RESERVED - 2
 * @endcode
 */
#define AESCCM_STATUS_RESERVED AES_STATUS_RESERVED

/*!
 * @brief   Successful status code.
 *
 * Functions return AESCCM_STATUS_SUCCESS if the function was executed
 * successfully.
 */
#define AESCCM_STATUS_SUCCESS AES_STATUS_SUCCESS

/*!
 * @brief   Generic error status code.
 *
 * Functions return AESCCM_STATUS_ERROR if the function was not executed
 * successfully and no more pertinent error code could be returned.
 */
#define AESCCM_STATUS_ERROR AES_STATUS_ERROR

/*!
 * @brief   An error status code returned if the hardware or software resource
 * is currently unavailable.
 *
 * AESCCM driver implementations may have hardware or software limitations on how
 * many clients can simultaneously perform operations. This status code is returned
 * if the mutual exclusion mechanism signals that an operation cannot currently be performed.
 */
#define AESCCM_STATUS_RESOURCE_UNAVAILABLE AES_STATUS_RESOURCE_UNAVAILABLE

/*!
 *  @brief  The ongoing operation was canceled.
 */
#define AESCCM_STATUS_CANCELED AES_STATUS_CANCELED

/*!
 * @brief   An error status code returned if the MAC provided by the application for
 *  a decryption operation does not match the one calculated during the operation.
 *
 * This code is returned by AESCCM_oneStepDecrypt() or AESCCM_finalizeDecrypt()
 * if the verification of the MAC fails.
 */
#define AESCCM_STATUS_MAC_INVALID AES_STATUS_MAC_INVALID

/*!
 *  @brief  The operation requested is not supported either by the target hardware
 *          or the driver implementation.
 */
#define AESCCM_STATUS_FEATURE_NOT_SUPPORTED AES_STATUS_FEATURE_NOT_SUPPORTED

/*!
 *  @brief  The operation tried to load a key from the keystore using an invalid key ID.
 */
#define AESCCM_STATUS_KEYSTORE_INVALID_ID AES_STATUS_KEYSTORE_INVALID_ID

/*!
 *  @brief  The key store module returned a generic error. See key store documentation
 *  for additional details.
 */
#define AESCCM_STATUS_KEYSTORE_GENERIC_ERROR AES_STATUS_KEYSTORE_GENERIC_ERROR

/*!
 * @brief   The operation does not support non-word-aligned input and/or output.
 *
 * AESCCM driver implementations may have restrictions on the alignment of
 * input/output data due to performance limitations of the hardware.
 */
#define AESCCM_STATUS_UNALIGNED_IO_NOT_SUPPORTED AES_STATUS_UNALIGNED_IO_NOT_SUPPORTED

/*!
 *  @brief AESCCM Global configuration
 *
 *  The AESCCM_Config structure contains a set of pointers used to characterize
 *  the AESCCM driver implementation.
 *
 *  This structure needs to be defined before calling AESCCM_init() and it must
 *  not be changed thereafter.
 *
 *  @sa     AESCCM_init()
 */
typedef AESCommon_Config AESCCM_Config;

/*!
 *  @brief  A handle that is returned from an AESCCM_open() call.
 */
typedef AESCCM_Config *AESCCM_Handle;

/*!
 * @brief   The way in which CCM function calls return after performing an
 * encryption + authentication or decryption + verification operation.
 *
 * Not all CCM operations exhibit the specified return behavior. Functions that do not
 * require significant computation and cannot offload that computation to a background thread
 * behave like regular functions. Which functions exhibit the specified return behavior is not
 * implementation dependent. Specifically, a software-backed implementation run on the same
 * CPU as the application will emulate the return behavior while not actually offloading
 * the computation to the background thread.
 *
 * AESCCM functions exhibiting the specified return behavior have restrictions on the
 * context from which they may be called.
 *
 * |                                | Task  | Hwi   | Swi   |
 * |--------------------------------|-------|-------|-------|
 * |AESCCM_RETURN_BEHAVIOR_CALLBACK | X     | X     | X     |
 * |AESCCM_RETURN_BEHAVIOR_BLOCKING | X     |       |       |
 * |AESCCM_RETURN_BEHAVIOR_POLLING  | X     | X     | X     |
 *
 */
typedef enum
{
    AESCCM_RETURN_BEHAVIOR_CALLBACK = AES_RETURN_BEHAVIOR_CALLBACK,
    /*!< The function call will return immediately while the
     *   CCM operation goes on in the background. The registered
     *   callback function is called after the operation completes.
     *   The context the callback function is called (task, HWI, SWI)
     *   is implementation-dependent.
     */
    AESCCM_RETURN_BEHAVIOR_BLOCKING = AES_RETURN_BEHAVIOR_BLOCKING,
    /*!< The function call will block while the CCM operation goes
     *   on in the background. CCM operation results are available
     *   after the function returns.
     */
    AESCCM_RETURN_BEHAVIOR_POLLING  = AES_RETURN_BEHAVIOR_POLLING,
    /*!< The function call will continuously poll a flag while CCM
     *   operation goes on in the background. CCM operation results
     *   are available after the function returns.
     */
} AESCCM_ReturnBehavior;

/*!
 *  @brief  Enum for the direction of the CCM operation.
 */
typedef enum
{
    AESCCM_MODE_ENCRYPT = 1,
    AESCCM_MODE_DECRYPT = 2,
} AESCCM_Mode;

/*!
 *  @brief  Struct containing the parameters required for encrypting/decrypting
 *          and authenticating/verifying a message for one-step operations.
 */
typedef struct
{
    CryptoKey *key;                /*!< A previously initialized CryptoKey */
    uint8_t *aad;                  /*!< A buffer of length \c aadLength containing additional
                                    *   authentication data to be authenticated/verified but not
                                    *   encrypted/decrypted.
                                    */
    uint8_t *input;                /*!<
                                    *   - Encryption: The plaintext buffer to be encrypted and authenticated
                                    *   in the CCM operation.
                                    *   - Decryption: The ciphertext to be decrypted and verified.
                                    */
    uint8_t *output;               /*!<
                                    *   - Encryption: The output ciphertext buffer that the encrypted plaintext
                                    *   is copied to.
                                    *   - Decryption: The plaintext derived from the decrypted and verified
                                    *   ciphertext is copied here.
                                    */
    uint8_t *nonce;                /*!< A buffer containing a nonce. Nonces must be unique to
                                    *   each CCM operation and may not be reused. If
                                    *   nonceInternallyGenerated is set, the nonce will be
                                    *   generated by #AESCCM_oneStepEncrypt() and copied to this buffer.
                                    */
    uint8_t *mac;                  /*!<
                                    *   - Encryption: The buffer where the message authentication
                                    *   code is copied.
                                    *   - Decryption: The buffer containing the received message
                                    *   authentication code.
                                    */
    size_t aadLength;              /*!< Length of the total \c aad in bytes. Either \c aadLength or
                                    *   \c inputLength must be non-zero. Unlike this field in
                                    *   AESCCM_SegmentedAADOperation, the length doesn't need to be
                                    *   block-aligned.
                                    */
    size_t inputLength;            /*!< Length of the input/output data in bytes. Either \c aadLength or
                                    *   \c inputLength must be non-zero. Unlike this field in
                                    *   AESCCM_SegmentedDataOperation, the length doesn't need to be
                                    *   block-aligned.
                                    *   Max length supported may be limited depending on the return behavior.
                                    */
    uint8_t nonceLength;           /*!< Length of \c nonce in bytes.
                                    *   Valid nonce lengths are [7, 8, ... 13].
                                    */
    uint8_t macLength;             /*!< Length of \c mac in bytes.
                                    *   Valid MAC lengths are [0, 4, 6, 8, 10, 12, 14, 16].
                                    *   A length of 0 disables authentication and verification. This is
                                    *   only permitted when using CCM*.
                                    */
    bool nonceInternallyGenerated; /*!< When true, the nonce buffer passed into #AESCCM_oneStepEncrypt()
                                    *   will be overwritten with a randomly generated nonce.
                                    *   Not supported by all implementations.
                                    */
} AESCCM_OneStepOperation;

/*!
 *  @brief  Struct containing the parameters required for
 *          authenticating/verifying additional data in a segmented operation.
 *          Must be updated for each add AAD step of a segmented operation.
 */
typedef struct
{
    uint8_t *aad;     /*!< A buffer of length \c aadLength containing additional
                       *   authentication data to be authenticated/verified but not
                       *   encrypted/decrypted.
                       */
    size_t aadLength; /*!< Length of the \c aad in bytes. Must be non-zero, multiple
                       *   of the AES block size (16 bytes) unless the last chunk of
                       *   AAD is being passed in. In that case, this value doesn't
                       *   need to be an AES block-sized multiple.
                       */
} AESCCM_SegmentedAADOperation;

/*!
 *  @brief  Struct containing the parameters required for encrypting/decrypting
 *          a message in a segmented operation. Must be updated between each
 *          add data step of a segmented operation.
 */
typedef struct
{
    uint8_t *input;     /*!<
                         *   - Encryption: The plaintext buffer to be encrypted and authenticated
                         *   in the CCM operation.
                         *   - Decryption: The ciphertext to be decrypted and verified.
                         */
    uint8_t *output;    /*!<
                         *   - Encryption: The output ciphertext buffer that the encrypted plaintext
                         *   is copied to.
                         *   - Decryption: The plaintext derived from the decrypted and verified
                         *   ciphertext is copied here.
                         */
    size_t inputLength; /*!< Length of the input/output data in bytes. Must be non-zero, multiple
                         *   of the AES block size (16 bytes) unless the last chunk of data is being
                         *   passed in. In that case, this value doesn't need to a block size multiple.
                         *   Max length supported may be limited depending on the return behavior.
                         */
} AESCCM_SegmentedDataOperation;

/*!
 *  @brief  Struct containing the parameters required for finalizing an
 *          encryption/decryption and authentication/verification of a message
 *          in a segmented operation.
 */
typedef struct
{
    uint8_t *input;     /*!<
                         *   - Encryption: The plaintext buffer to be encrypted and authenticated
                         *   in the CCM operation.
                         *   - Decryption: The ciphertext to be decrypted and verified.
                         */
    uint8_t *output;    /*!<
                         *   - Encryption: The output ciphertext buffer that the encrypted plaintext
                         *   is copied to.
                         *   - Decryption: The plaintext derived from the decrypted and verified
                         *   ciphertext is copied here.
                         */
    uint8_t *mac;       /*!<
                         *   - Encryption: The buffer where the message authentication
                         *   code is copied.
                         *   - Decryption: The buffer containing the received message
                         *   authentication code.
                         */
    size_t inputLength; /*!< Length of the input/output data in bytes. Can be 0 if finalizing
                         *   without new payload data. Unlike this field in
                         *   AESCCM_SegmentedDataOperation, the length doesn't need to be
                         *   block-aligned.
                         *   Max length supported may be limited depending on the return behavior.
                         */
    uint8_t macLength;  /*!< Length of \c mac in bytes.
                         *   Valid MAC lengths are [0, 4, 6, 8, 10, 12, 14, 16].
                         *   A length of 0 disables authentication and verification. This is
                         *   only permitted when using CCM*.
                         */
} AESCCM_SegmentedFinalizeOperation;

/**
 * @deprecated
 * Define a typedef for deprecated operation AESCCM_Operation.
 * Existing code should be refactored to use AESCCM_OneStepOperation.
 * This reference may be removed at some point in the future
 *
 */
typedef AESCCM_OneStepOperation AESCCM_Operation;

/*!
 *  @brief Union containing a reference to a one step,
 *  segmented AAD, segmented data, or segmented finalize operation.
 */
typedef union AESCCM_OperationUnion
{
    AESCCM_OneStepOperation oneStepOperation;             /* One-step operation element of the operation union */
    AESCCM_SegmentedAADOperation segmentedAADOperation;   /* Segmented AAD operation element of the operation union */
    AESCCM_SegmentedDataOperation segmentedDataOperation; /* Segmented data operation element of the operation union */
    AESCCM_SegmentedFinalizeOperation segmentedFinalizeOperation; /* Segmented finalize operation element of the
                                                                     operation union */
} AESCCM_OperationUnion;

/*!
 *  @brief  Enum for the operation types supported by the driver.
 */
typedef enum
{
    AESCCM_OPERATION_TYPE_ENCRYPT   = 1, /* Fields 1 and 2 are for backward compatibility */
    AESCCM_OPERATION_TYPE_DECRYPT   = 2,
    AESCCM_OP_TYPE_ONESTEP_ENCRYPT  = 1, /* Names changed to _OP_TYPE_ to avoid MISRA deviation from first 31 chars not
                                            being unique */
    AESCCM_OP_TYPE_ONESTEP_DECRYPT  = 2,
    AESCCM_OP_TYPE_AAD_ENCRYPT      = 3,
    AESCCM_OP_TYPE_AAD_DECRYPT      = 4,
    AESCCM_OP_TYPE_DATA_ENCRYPT     = 5,
    AESCCM_OP_TYPE_DATA_DECRYPT     = 6,
    AESCCM_OP_TYPE_FINALIZE_ENCRYPT = 7,
    AESCCM_OP_TYPE_FINALIZE_DECRYPT = 8,
} AESCCM_OperationType;

/*!
 *  @brief  The definition of a callback function used by the AESCCM driver
 *          when used in ::AESCCM_RETURN_BEHAVIOR_CALLBACK
 *
 *  @param  handle         Handle of the client that started the CCM operation.
 *
 *  @param  returnValue    The result of the CCM operation. May contain an error code.
 *                         Informs the application of why the callback function was
 *                         called.
 *
 *  @param  operationUnion A pointer to an operation union.
 *
 *  @param  operationType  This parameter determines which operation the
 *                         callback refers to.
 */
typedef void (*AESCCM_CallbackFxn)(AESCCM_Handle handle,
                                   int_fast16_t returnValue,
                                   AESCCM_OperationUnion *operation,
                                   AESCCM_OperationType operationType);

/*!
 *  @brief  CCM Parameters
 *
 *  CCM Parameters used with the AESCCM_open() call. Default values for
 *  these parameters are set using AESCCM_Params_init().
 *
 *  @sa     AESCCM_Params_init()
 */
typedef struct
{
    AESCCM_ReturnBehavior returnBehavior; /*!< Blocking, callback, or polling return behavior */
    AESCCM_CallbackFxn callbackFxn;       /*!< Callback function pointer */
    uint32_t timeout;                     /*!< Timeout before the driver returns an error in
                                           *   ::AESCCM_RETURN_BEHAVIOR_BLOCKING
                                           */
    void *custom;                         /*!< Custom argument used by driver
                                           *   implementation
                                           */
} AESCCM_Params;

/*!
 *  @brief Default AESCCM_Params structure
 *
 *  @sa    #AESCCM_Params_init()
 */
extern const AESCCM_Params AESCCM_defaultParams;

/*!
 *  @brief  This function initializes the CCM module.
 *
 *  @pre    The AESCCM_config structure must exist and be persistent before this
 *          function can be called. This function must also be called before
 *          any other CCM driver APIs. This function call does not modify any
 *          peripheral registers.
 */
void AESCCM_init(void);

/*!
 *  @brief  Function to initialize the #AESCCM_Params struct to its defaults
 *
 *  @param  params      An pointer to #AESCCM_Params structure for
 *                      initialization
 *
 *  Defaults values are:
 *      returnBehavior              = AESCCM_RETURN_BEHAVIOR_BLOCKING
 *      callbackFxn                 = NULL
 *      timeout                     = SemaphoreP_WAIT_FOREVER
 *      custom                      = NULL
 */
void AESCCM_Params_init(AESCCM_Params *params);

/*!
 *  @brief  This function opens a given CCM peripheral.
 *
 *  @pre    CCM controller has been initialized using #AESCCM_init()
 *
 *  @param  [in] index    Logical peripheral number for the CCM indexed into
 *                        the AESCCM_config table
 *
 *  @param  [in] params   Pointer to an parameter block, if NULL it will use
 *                        default values.
 *
 *  @return An AESCCM_Handle on success or a NULL on an error or if it has been
 *          opened already.
 *
 *  @sa     #AESCCM_init()
 *  @sa     #AESCCM_close()
 */
AESCCM_Handle AESCCM_open(uint_least8_t index, const AESCCM_Params *params);

/*!
 *  @brief  Function to close a CCM peripheral specified by the CCM handle
 *
 *  @pre    #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] handle A CCM handle
 *
 *  @sa     #AESCCM_open()
 */
void AESCCM_close(AESCCM_Handle handle);

/*!
 *  @brief  Function to prepare a segmented AESCCM encryption operation.
 *
 *  This function sets up a segmented AESCCM encryption operation.
 *
 *  @pre    #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] handle                A CCM handle returned from #AESCCM_open()
 *                                     or #AESCCM_construct()
 *
 *  @param  [in] key                   Pointer to a previously initialized CryptoKey.
 *
 *  @param  [in] totalAADLength        Total size of the AAD in bytes.
 *                                     This value can be 0 and later provided
 *                                     by #AESCCM_setLengths().
 *
 *  @param  [in] totalPlaintextLength  Total size of the plaintext in bytes.
 *                                     This value can be 0 and later provided
 *                                     by #AESCCM_setLengths().
 *
 *  @param  [in] macLength             Size of the MAC in bytes. This value
 *                                     can be 0 and later provided by
 *                                     #AESCCM_setLengths().
 *
 *  @retval #AESCCM_STATUS_SUCCESS                  The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                    The operation failed.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED    The operation is not supported in this device.
 *
 *  @post   #AESCCM_addAAD()
 *  @post   #AESCCM_addData()
 */
int_fast16_t AESCCM_setupEncrypt(AESCCM_Handle handle,
                                 const CryptoKey *key,
                                 size_t totalAADLength,
                                 size_t totalPlaintextLength,
                                 size_t macLength);

/*!
 *  @brief  Function to prepare a segmented AESCCM decryption operation.
 *
 *  This function sets up a segmented AESCCM decryption operation.
 *
 *  @pre    #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] handle                A CCM handle returned from #AESCCM_open()
 *                                     or #AESCCM_construct()
 *
 *  @param  [in] key                   Pointer to a previously initialized CryptoKey.
 *
 *  @param  [in] totalAADLength        Total size of the AAD in bytes.
 *                                     This value can be 0 and later provided
 *                                     by #AESCCM_setLengths().
 *
 *  @param  [in] totalPlaintextLength  Total size of the plaintext in bytes
 *                                     This value can be 0 and later provided
 *                                     by #AESCCM_setLengths().
 *
 *  @param  [in] macLength             Size of the MAC in bytes. This value
 *                                     can be 0 and later provided by
 *                                     #AESCCM_setLengths().
 *
 *  @retval #AESCCM_STATUS_SUCCESS                  The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                    The operation failed.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED    The operation is not supported in this device.
 *
 *  @post   #AESCCM_addAAD()
 *  @post   #AESCCM_addData()
 */
int_fast16_t AESCCM_setupDecrypt(AESCCM_Handle handle,
                                 const CryptoKey *key,
                                 size_t totalAADLength,
                                 size_t totalPlaintextLength,
                                 size_t macLength);

/*!
 *  @brief  Function to set the lengths of the message, additional data, and MAC.
 *
 *  This function declares the lengths of the message,
 *  additional authenticated data (AAD), and MAC.
 *
 *  @note   This function doesn't have to be called if the lengths above were
 *          specified in #AESCCM_setupEncrypt() or #AESCCM_setupDecrypt().
 *
 *  @pre    #AESCCM_setupEncrypt() or #AESCCM_setupDecrypt()
 *
 *  @param  [in] handle           A CCM handle returned from #AESCCM_open()
 *                                or #AESCCM_construct()
 *
 *  @param  [in] aadLength        Size of the non-encrypted AAD in bytes
 *
 *  @param  [in] plaintextLength  Size of the plaintext or ciphertext to encrypt or decrypt in bytes
 *
 *  @param  [in] macLength        Size of the MAC in bytes
 *
 *  @retval #AESCCM_STATUS_SUCCESS                  The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                    The operation failed.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED    The operation is not supported in this device.
 *
 *  @post   #AESCCM_setNonce()
 *  @post   #AESCCM_generateNonce()
 */
int_fast16_t AESCCM_setLengths(AESCCM_Handle handle, size_t aadLength, size_t plaintextLength, size_t macLength);

/*!
 *  @brief  Function to set the nonce for an AES CCM segmented operation.
 *
 *  @pre    #AESCCM_setupEncrypt(), #AESCCM_setupDecrypt(), or #AESCCM_setLengths()
 *
 *  @param  [in] handle           A CCM handle returned from #AESCCM_open()
 *                                or #AESCCM_construct()
 *
 *  @param  [in] nonce            Pointer to the buffer containing the nonce
 *
 *  @param  [in] nonceLength      The length of the nonce in bytes
 *
 *  @retval #AESCCM_STATUS_SUCCESS                  The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                    The operation failed.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED    The operation is not
 *                                                  supported in this device.
 *
 *  @post   #AESCCM_addAAD()
 *  @post   #AESCCM_addData()
 */
int_fast16_t AESCCM_setNonce(AESCCM_Handle handle, const uint8_t *nonce, size_t nonceLength);

/*!
 *  @brief  Function to generate a nonce for an AES CCM segmented encryption operation.
 *
 *  @pre    #AESCCM_setupEncrypt() or #AESCCM_setLengths()
 *
 *  @param  [in] handle       A CCM handle returned from #AESCCM_open()
 *                            or #AESCCM_construct()
 *
 *  @param  [in] nonce        Pointer to the buffer where the generated nonce
 *                            is to be written to
 *
 *  @param  [in] nonceSize    The length of the nonce buffer in bytes
 *
 *  @param  [out] nonceLength The length of the nonce actually written if the
 *                            operation was successful
 *
 *  @retval #AESCCM_STATUS_SUCCESS                  The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                    The operation failed.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED    The operation is not
 *                                                  supported in this device.
 *
 *  @post   #AESCCM_addAAD()
 *  @post   #AESCCM_addData()
 */
int_fast16_t AESCCM_generateNonce(AESCCM_Handle handle, uint8_t *nonce, size_t nonceSize, size_t *nonceLength);

/*!
 *  @brief  Adds a segment of @a aad with a @a length in bytes to the generated MAC.
 *  The length must be a multiple of a block size, 16 bytes, unless passing in the last
 *  chunk of AAD.
 *
 *  #AESCCM_addAAD() may be called an arbitrary number of times before continuing the operation with
 *  #AESCCM_addData(), #AESCCM_finalizeEncrypt() or #AESCCM_finalizeDecrypt().
 *
 *  This function returns according to the return behavior set when opening the driver.
 *
 *  @note     This function must not be called after passing data to encrypt or
 *            decrypt with #AESCCM_addData().
 *
 *  @warning  When decrypting, do not use the output until
 *            #AESCCM_finalizeDecrypt() succeeds.
 *
 *  @pre      #AESCCM_setNonce() or #AESCCM_generateNonce()
 *
 *  @param    [in] handle         A CCM handle returned from #AESCCM_open() or #AESCCM_construct()
 *
 *  @param    [in] operation      Pointer to segmented AAD CCM operation structure
 *
 *  @retval   #AESCCM_STATUS_SUCCESS               The operation succeeded.
 *  @retval   #AESCCM_STATUS_ERROR                 The operation failed.
 *  @retval   #AESCCM_STATUS_RESOURCE_UNAVAILABLE  The required hardware resource was not available.
 *                                                 Try again later.
 *  @retval   #AESCCM_STATUS_FEATURE_NOT_SUPPORTED The operation is not supported in this device.
 *  @retval   #AESCCM_STATUS_CANCELED              The operation was canceled.
 *
 *  @post     #AESCCM_addAAD()
 *  @post     #AESCCM_addData()
 *  @post     #AESCCM_finalizeEncrypt()
 *  @post     #AESCCM_finalizeDecrypt()
 */
int_fast16_t AESCCM_addAAD(AESCCM_Handle handle, AESCCM_SegmentedAADOperation *operation);

/*!
 *  @brief  Adds a segment of @a data with a @a length in bytes to the plaintext/ciphertext
 *  output and generated MAC. The length must be a multiple of a block size, 16 bytes, unless
 *  passing in the last chunk of payload data.
 *
 *  #AESCCM_addData() may be called an arbitrary number of times before finishing the operation
 *  with #AESCCM_finalizeEncrypt() or #AESCCM_finalizeDecrypt().
 *
 *  This function returns according to the return behavior set when opening the driver.
 *
 *  @warning  When decrypting, do not use the output until
 *            #AESCCM_finalizeDecrypt() succeeds.
 *
 *  @pre      #AESCCM_setNonce() or #AESCCM_generateNonce()
 *
 *  @param    [in] handle         A CCM handle returned from #AESCCM_open() or #AESCCM_construct()
 *
 *  @param    [in] operation      Pointer to segmented data CCM operation structure
 *
 *  @retval   #AESCCM_STATUS_SUCCESS               The operation succeeded.
 *  @retval   #AESCCM_STATUS_ERROR                 The operation failed.
 *  @retval   #AESCCM_STATUS_RESOURCE_UNAVAILABLE  The required hardware resource was not available.
 *                                                 Try again later.
 *  @retval   #AESCCM_STATUS_FEATURE_NOT_SUPPORTED The operation is not supported in this device.
 *  @retval   #AESCCM_STATUS_CANCELED              The operation was canceled.
 *  @retval   #AESCCM_STATUS_UNALIGNED_IO_NOT_SUPPORTED  The input and/or output buffer were not word-aligned.
 *
 *  @post     #AESCCM_addData()
 *  @post     #AESCCM_finalizeEncrypt()
 *  @post     #AESCCM_finalizeDecrypt()
 */
int_fast16_t AESCCM_addData(AESCCM_Handle handle, AESCCM_SegmentedDataOperation *operation);

/*!
 *  @brief  Finalize the MAC and ciphertext.
 *
 *  This function finalizes the encryption of a dataset earlier provided
 *  by calls to #AESCCM_addAAD() and #AESCCM_addData() and creates a message
 *  authentication code. If additional data needs to be encrypted and verified
 *  as part of this call, set the operation structure @a inputLength accordingly.
 *
 *  The resulting output is a message authentication code and ciphertext.
 *
 *  @pre    #AESCCM_addAAD() or #AESCCM_addData()
 *
 *  @param  [in] handle         A CCM handle returned from #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] operation      Pointer to segmented finalize CCM operation structure
 *
 *  @retval #AESCCM_STATUS_SUCCESS               In ::AESCCM_RETURN_BEHAVIOR_BLOCKING and
 *                                               ::AESCCM_RETURN_BEHAVIOR_POLLING, this means the MAC
 *                                               was generated successfully. In ::AESCCM_RETURN_BEHAVIOR_CALLBACK,
 *                                               this means the operation started successfully.
 *  @retval #AESCCM_STATUS_ERROR                 The operation failed.
 *  @retval #AESCCM_STATUS_CANCELED              The operation was canceled.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED The operation is not supported in this device.
 *  @retval #AESCCM_STATUS_UNALIGNED_IO_NOT_SUPPORTED  The input and/or output buffer were not word-aligned.
 */
int_fast16_t AESCCM_finalizeEncrypt(AESCCM_Handle handle, AESCCM_SegmentedFinalizeOperation *operation);

/*!
 *  @brief  Finalize the MAC and plaintext and verify it.
 *
 *  This function finalizes the decryption of a dataset earlier provided
 *  by calls to AESCCM_addAAD() and AESCCM_addData() and verifies a provided message
 *  authentication code. If additional data needs to be decrypted and verified
 *  as part of this call, set the operation structure @a inputLength accordingly.
 *
 *  @note   None of the buffers provided as arguments may be altered by the application during an ongoing operation.
 *          Doing so can yield a corrupted MAC comparison.
 *
 *  The resulting output is a verification return code and plaintext.
 *
 *  @pre    #AESCCM_addAAD() or #AESCCM_addData()
 *
 *  @param  [in] handle         A CCM handle returned from #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] operation      Pointer to segmented finalize CCM operation structure
 *
 *  @retval #AESCCM_STATUS_SUCCESS               In ::AESCCM_RETURN_BEHAVIOR_BLOCKING and
 *                                               ::AESCCM_RETURN_BEHAVIOR_POLLING, this means the MAC
 *                                               was verified successfully. In ::AESCCM_RETURN_BEHAVIOR_CALLBACK,
 *                                               this means the operation started successfully.
 *  @retval #AESCCM_STATUS_ERROR                 The operation failed.
 *  @retval #AESCCM_STATUS_MAC_INVALID           The provided MAC did not match the recomputed one.
 *  @retval #AESCCM_STATUS_CANCELED              The operation was canceled.
 *  @retval #AESCCM_STATUS_FEATURE_NOT_SUPPORTED The operation is not supported in this device.
 *  @retval #AESCCM_STATUS_UNALIGNED_IO_NOT_SUPPORTED  The input and/or output buffer were not word-aligned.
 */
int_fast16_t AESCCM_finalizeDecrypt(AESCCM_Handle handle, AESCCM_SegmentedFinalizeOperation *operation);

/*!
 *  @brief  Function to initialize an #AESCCM_Operation struct to its defaults
 *
 *  @deprecated  This function should be replaced by calls to operation-specific
 *               init functions.
 *
 *  @param       [in] operationStruct     A pointer to an #AESCCM_Operation structure for
 *                                        initialization
 *
 *  Defaults values are all zeros.
 */
void AESCCM_Operation_init(AESCCM_Operation *operationStruct);

/*!
 *  @brief  Function to initialize an #AESCCM_OneStepOperation struct to its defaults
 *
 *  @param       [in] operationStruct     A pointer to an #AESCCM_OneStepOperation structure for
 *                                        initialization
 *
 *  Defaults values are all zeros.
 */
void AESCCM_OneStepOperation_init(AESCCM_OneStepOperation *operationStruct);

/*!
 *  @brief  Function to initialize an #AESCCM_SegmentedAADOperation struct to its defaults
 *
 *  @param       [in] operationStruct     A pointer to an #AESCCM_SegmentedAADOperation structure
 *                                        for initialization
 *
 *  Defaults values are all zeros.
 */
void AESCCM_SegmentedAADOperation_init(AESCCM_SegmentedAADOperation *operationStruct);

/*!
 *  @brief  Function to initialize an #AESCCM_SegmentedDataOperation struct to its defaults
 *
 *  @param       [in] operationStruct     A pointer to an #AESCCM_SegmentedDataOperation structure
 *                                        for initialization
 *
 *  Defaults values are all zeros.
 */
void AESCCM_SegmentedDataOperation_init(AESCCM_SegmentedDataOperation *operationStruct);

/*!
 *  @brief  Function to initialize an #AESCCM_SegmentedFinalizeOperation struct to its defaults
 *
 *  @param       [in] operationStruct     A pointer to an #AESCCM_SegmentedFinalizeOperation structure
 *                                        for initialization
 *
 *  Defaults values are all zeros.
 */
void AESCCM_SegmentedFinalizeOperation_init(AESCCM_SegmentedFinalizeOperation *operationStruct);

/*!
 *  @brief  Function to perform an AESCCM encryption + authentication operation in one call.
 *
 *  @note   None of the buffers provided as arguments may be altered by the application during an ongoing operation.
 *          Doing so can yield corrupted ciphertext or incorrect authentication.
 *
 *  @pre    #AESCCM_open() or #AESCCM_construct() and #AESCCM_Operation_init() have to be called first.
 *
 *  @param  [in] handle                 A CCM handle returned from #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] operationStruct        A pointer to a struct containing the parameters required to perform the
 * operation.
 *
 *  @retval #AESCCM_STATUS_SUCCESS               The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                 The operation failed.
 *  @retval #AESCCM_STATUS_RESOURCE_UNAVAILABLE  The required hardware resource was not available. Try again later.
 *  @retval #AESCCM_STATUS_UNALIGNED_IO_NOT_SUPPORTED  The input and/or output buffer were not word-aligned.
 *
 *  @sa     AESCCM_oneStepDecrypt()
 */
int_fast16_t AESCCM_oneStepEncrypt(AESCCM_Handle handle, AESCCM_OneStepOperation *operationStruct);

/*!
 *  @brief  Function to perform an AESCCM decryption + verification operation in one call.
 *
 *  @note   None of the buffers provided as arguments may be altered by the application during an ongoing operation.
 *          Doing so can yield corrupted plaintext or incorrectly failed verification.
 *
 *  @pre    #AESCCM_open() or #AESCCM_construct() and #AESCCM_Operation_init() have to be called first.
 *
 *  @param  [in] handle                 A CCM handle returned from #AESCCM_open() or #AESCCM_construct()
 *
 *  @param  [in] operationStruct        A pointer to a struct containing the parameters required to perform the
 * operation.
 *
 *  @retval #AESCCM_STATUS_SUCCESS               The operation succeeded.
 *  @retval #AESCCM_STATUS_ERROR                 The operation failed.
 *  @retval #AESCCM_STATUS_RESOURCE_UNAVAILABLE  The required hardware resource was not available. Try again later.
 *  @retval #AESCCM_STATUS_MAC_INVALID           The provided MAC did not match the recomputed one.
 *  @retval #AESCCM_STATUS_UNALIGNED_IO_NOT_SUPPORTED  The input and/or output buffer were not word-aligned.
 *
 *  @sa     AESCCM_oneStepEncrypt()
 */
int_fast16_t AESCCM_oneStepDecrypt(AESCCM_Handle handle, AESCCM_OneStepOperation *operationStruct);

/*!
 *  @brief Cancels an ongoing AESCCM operation.
 *
 *  Asynchronously cancels an AESCCM operation. Only available when using
 *  AESCCM_RETURN_BEHAVIOR_CALLBACK.
 *  The operation will terminate as though an error occurred. The
 *  return status code of the operation will be AESCCM_STATUS_CANCELED.
 *
 *  @param  [in] handle Handle of the operation to cancel
 *
 *  @retval #AESCCM_STATUS_SUCCESS               The operation was canceled, or the operation had already completed.
 *  @retval #AESCCM_STATUS_ERROR                 The driver was not in callback mode, or the operation's output
 *                                               and generated MAC weren't properly cleared.
 */
int_fast16_t AESCCM_cancelOperation(AESCCM_Handle handle);

/**
 *  @brief  Constructs a new AESCCM object
 *
 *  Unlike #AESCCM_open(), #AESCCM_construct() does not require the hwAttrs and
 *  object to be allocated in a #AESCCM_Config array that is indexed into.
 *  Instead, the #AESCCM_Config, hwAttrs, and object can be allocated at any
 *  location. This allows for relatively simple run-time allocation of temporary
 *  driver instances on the stack or the heap.
 *  The drawback is that this makes it more difficult to write device-agnostic
 *  code. If you use an ifdef with DeviceFamily, you can choose the correct
 *  object and hwAttrs to allocate. That compilation unit will be tied to the
 *  device it was compiled for at this point. To change devices, recompilation
 *  of the application with a different DeviceFamily setting is necessary.
 *
 *  @param  config #AESCCM_Config describing the location of the object and hwAttrs.
 *
 *  @param  params #AESCCM_Params to configure the driver instance.
 *
 *  @return        Returns a #AESCCM_Handle on success or NULL on failure.
 *
 *  @pre    The object struct @c config points to must be zeroed out prior to
 *          calling this function. Otherwise, unexpected behavior may ensue.
 */
AESCCM_Handle AESCCM_construct(AESCCM_Config *config, const AESCCM_Params *params);

#ifdef __cplusplus
}
#endif

#endif /* ti_drivers_AESCCM__include */
